﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;
using Newtonsoft.Json;

using Zen.Toolkit.Widgets;


namespace Zen.Toolkit.Common
{

    public enum Placement
    {
        OnLoad,
        InHead,
        InBody,
        BeforeInit,
        InInit,
        AfterInit
    }

    public class ScriptFragment
    {
        public IScriptTemplate Template { get; set; }
        public Placement Position { get; set; }
        public object[] Script { get; set; }


        public ScriptFragment()
        {
            Template = ScriptTemplate.NullFragment;
            Script = new object[] { "" };
        }

        public string Build()
        {
            return Template.Build(Script);
        }

    }

    public class ScriptGenerator : WidgetBase
    {
        private Dictionary<string, ScriptFragment> _fragments = new Dictionary<string, ScriptFragment>();
        private bool _scriptRendered = false;

        public ScriptGenerator() : base(HtmlTextWriterTag.Div) { }

        private bool IsFragmentRegistered(string key) { return false;  }
    

        public void AddFragment(string key, Placement position, string scriptContent)
        {
            _fragments[key] = new ScriptFragment
                {
                    Position = position,
                    Template = ScriptTemplate.NullFragment,
                    Script = new object[] { scriptContent }
                };

        }

        public void AddFragment(string key, Placement placement, IScriptTemplate template, params object[] args)
        {
            _fragments[key] = new ScriptFragment
            {
                Position = placement,
                Template = template,
                Script = args
            };
        }

        public void AddIncludeReference(string url)
        {
            AddFragment(string.Format("@incref:{0}", url), 
                Placement.InHead, 
                ScriptTemplate.IncludeScript, 
                url);
        }

        public void AddIncludeResource(Page page, string resourceName)
        {
            string resourceUrl = page.ClientScript.GetWebResourceUrl(this.GetType(), resourceName);
            AddFragment(string.Format("@incres:{0}", resourceName),
                Placement.InHead, ScriptTemplate.IncludeScript, resourceUrl);
        }
        public void AddRequireScript(string moduleName)
        {
            AddFragment(
            string.Format("@reqmod:{0}", moduleName),
            Placement.InHead, ScriptTemplate.DojoRequire, moduleName);
        }

        public void AddAfterWidgetInit(WidgetBase widget, string key, string format, params object[] args)
        {
            AddFragment(widget.ClientID + key, Placement.AfterInit, string.Format(format, args));
        }

        public void AddWidgetInit(WidgetBase widget, string widgetName, string constructorArgs, string elementName)
        {
            AddFragment(
                widget.ClientID + "_init",
                Placement.InInit, 
                ScriptTemplate.DojoConstructor, 
                new object[] {
                    widget.ClientID,
                    widgetName,
                    constructorArgs,
                    elementName
            });
        }

        public void AddOnLoadScript(string key, string script)
        {
            AddFragment(key, Placement.OnLoad, script);
        }

        public void AddStyleReference(string url)
        {
            AddFragment(
                string.Format("@cssref:{0}", url),
                Placement.InHead, ScriptTemplate.ImportStyle, url
                );
        }


        internal void WriteScript(HtmlTextWriter writer, ScriptFragment[] fragments)
        {
            foreach (ScriptFragment f in fragments)
            {
                writer.WriteLine(f.Build());
            }
        
        }

        public static string Format(string format, params object[] args)
        {
            return string.Format(new ZenFormatter(), format, args);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (!DesignMode)
            {
                if (_scriptRendered)
                    throw (new ZenScriptException("Script has already been rendered"));

                StringBuilder sbIncludeScript = new StringBuilder();

                WriteScript(writer,
                    (from n in _fragments.Values
                    where n.Position == Placement.InHead && ((n.Template.Flags & ScriptTemplateFlags.Block) == ScriptTemplateFlags.Block)
                    select n).ToArray()
                );

                // write all inline header script
                writer.WriteLine("<script type=\"text/javascript\">");
                WriteScript(writer,
                    (from n in _fragments.Values
                     where n.Position == Placement.InHead && ((n.Template.Flags & ScriptTemplateFlags.Inline) == ScriptTemplateFlags.Inline)
                     select n).ToArray()
                );

                // write all dojo onload script
                writer.WriteLine("dojo.addOnLoad(function() {");

                WriteScript(writer,
                    (from n in _fragments.Values
                     where n.Position == Placement.BeforeInit
                     select n).ToArray()
                );
                
                WriteScript(writer,
                    (from n in _fragments.Values
                     where n.Position == Placement.InInit
                     select n).ToArray()
                );

                WriteScript(writer,
                    (from n in _fragments.Values
                     where n.Position == Placement.AfterInit
                     select n).ToArray()
                );

                WriteScript(writer,
                    (from n in _fragments.Values
                     where n.Position == Placement.OnLoad
                     select n).ToArray()
                );


                // end dojo onload
                writer.WriteLine("});");
                writer.WriteLine("</script>");




                //foreach (string includeResource in _resources)
                //{
                //    writer.Write(ScriptWriter.Format(ScriptTemplates.IncludeScript, includeResource));
                //}

                //foreach (string includeStyle in _styles)
                //{
                //    writer.Write(ScriptWriter.Format(ScriptTemplates.ImportStyle, includeStyle));
                //}


                //// start-up script and requires
                //writer.Write(ScriptWriter.Format(ScriptTemplates.InlineScript,
                //    string.Concat(
                //        GetRequireScript(),
                //        ScriptWriter.Format(ScriptTemplates.DojoOnLoad, GetOnLoadScript()))
                //        )
                //    );


                _scriptRendered = true;
            }
        }

    }
}
